home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
016a
/
gofer221.zip
/
STATIC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-20
|
58KB
|
1,770 lines
/* --------------------------------------------------------------------------
* static.c: Copyright (c) Mark P Jones 1991. All rights reserved.
* See goferite.h for details and conditions of use etc...
* Gofer version 2.21 November 1991
*
* Last updated 07/11/91 mpj
*
* Static Analysis for Gofer
* ------------------------------------------------------------------------*/
#include "prelude.h"
#include "storage.h"
#include "connect.h"
#include "errors.h"
/* --------------------------------------------------------------------------
* local function prototypes:
* ------------------------------------------------------------------------*/
static Void local checkSynonym Args((Tycon));
static Void local checkData Args((Tycon));
static List local checkTypeLhs Args((Int,Cell));
static Cell local varFindDup Args((List));
static Cell local checkDeclType Args((Int,List,Cell));
static Cell local findOffset Args((Text,List));
static Name local makeConstr Args((Cell,Cell,List,Int,Int));
static Int local maximum Args((Int,Int));
static Int local tyconRank Args((Tycon));
static Int local maxRank Args((Cell));
static Type local fullExpand Args((Type));
static Type local instantiateSyn Args((Type,Type));
static List local typeVarsIn Args((Cell,List));
static List local maybeAppendVar Args((Cell,List));
static Cell local checkSigType Args((Int,String,Cell,Cell));
static Void local checkClassConstraint Args((Int,List,Class));
static Class local classDefined Args((Int,Cell));
static List local offsetTyvarsIn Args((Type,List));
static Void local checkClassDefn Args((Class));
static List local addMemberFunctions Args((Class,List,List));
static Name local newMember Args((Int,Cell,Int,Type));
static Void local checkInstDefn Args((Inst));
static List local classBindings Args((String,Class,List));
static Int local memberNumber Args((Class,Text));
static List local numInsert Args((Int,Cell,List));
static Void local addNewPrim Args((Int,Text,String,Cell));
static Cell local checkPat Args((Int,Cell));
static Cell local checkMaybeCnkPat Args((Int,Cell));
static Cell local checkApPat Args((Int,Int,Cell));
static Void local addPatVar Args((Int,Cell));
static Name local conDefined Args((Int,Text));
static Void local checkIsCfun Args((Int,Cell));
static Void local checkCfunArgs Args((Int,Cell,Int));
static Cell local bindPat Args((Int,Cell));
static Void local bindPats Args((Int,List));
static List local extractSigdecls Args((List));
static List local extractBindings Args((List));
static List local eqnsToBindings Args((List));
static Void local notDefined Args((Int,List,Cell));
static Cell local findBinding Args((Text,List));
static Void local addSigDecl Args((List,Cell));
static Void local setType Args((Int,Cell,Cell,List));
static List local dependencyAnal Args((List));
static List local topDependAnal Args((List));
static Void local addDepField Args((Cell));
static Void local remDepField Args((List));
static Void local remDepField1 Args((Cell));
static Void local clearScope Args((Void));
static Void local withinScope Args((List));
static Void local leaveScope Args((Void));
static Void local depBinding Args((Cell));
static Void local depDefaults Args((Class));
static Void local depInsts Args((Inst));
static Void local depClassBindings Args((List));
static Void local depAlt Args((Cell));
static Void local depRhs Args((Cell));
static Void local depGuard Args((Cell));
static Cell local depExpr Args((Int,Cell));
static Void local depPair Args((Int,Cell));
static Void local depTriple Args((Int,Cell));
static Void local depListComp Args((Int,Cell));
static Void local depQual Args((Int,Cell));
static Void local depCaseAlt Args((Int,Cell));
static Cell local depVar Args((Int,Cell));
static Int local sccMin Args((Int,Int));
static Int local lowlink Args((Cell));
static List local scc Args((List));
static Void local opDefined Args((List,Cell));
static Void local allNoPrevDef Args((Cell));
static Void local noPrevDef Args((Int,Cell));
/* --------------------------------------------------------------------------
* Static analysis of type declarations:
*
* Type declarations come in two forms:
* - data declarations - define new constructed data types
* - type declarations - define new type synonyms
*
* A certain amount of work is carried out as the declarations are
* read during parsing. In particular, for each type constructor
* definition encountered:
* - check that there is no previous definition of constructor
* - type constructor not previously used as a class name
* - make a new entry in the type constructor table
* - calculate arity
* - set rank to RANKUNKNOWN (for TYPE decls)
* 0 (for DATA decls)
* - record line number of declaration
* - Build separate lists of newly defined data and synonym
* constructors for later use.
* ------------------------------------------------------------------------*/
#define RANKUNKNOWN (-1) /* Proper rank values are integers in [0..] */
#define RANKVISITING (-2) /* (Constructed data types have rank 0) */
Void newTypeDefn(line,l,r,dataDefn) /* process new type definition */
Int line; /* definition line number */
Cell l; /* left hand side of definition */
Cell r; /* right hand side */
Bool dataDefn; { /* TRUE => data definition */
Cell t = getHead(l);
Tycon new = findTycon(textOf(t));
if (isNull(new)) {
if (nonNull(findClass(textOf(t)))) {
ERROR(line) "\"%s\" used as both class and type constructor",
textToStr(textOf(t))
EEND;
}
new = newTycon(textOf(t));
}
else if (tycon(new).defn!=PREDEFINED) {
ERROR(line) "Repeated definition of type constructor \"%s\"",
textToStr(textOf(t))
EEND;
}
tycon(new).line = line;
tycon(new).arity = argCount;
tycon(new).defn = pair(l,r);
if (dataDefn) {
tycon(new).rank = 0;
dataDefns = cons(new,dataDefns);
}
else {
tycon(new).rank = RANKUNKNOWN;
synonymDefns = cons(new,synonymDefns);
}
}
/* --------------------------------------------------------------------------
* Further analysis of Type declarations:
*
* In order to allow the definition of mutually recursive families of
* data types, the static analysis of the right hand sides of type
* declarations cannot be performed until all of the type declarations
* have been read.
*
* Once parsing is complete, we carry out the following:
* - check that there are no repeated type variables on lhs.
* - check that there are no free type variables on rhs.
* - check that all type constructors are defined and used with the
* correct arity.
* - check that there are no previous definitions for constructor
* functions in data type definitions.
* - install synonym expansions and constructor definitions.
* - replace type variables by Offsets, constructors by Tycons.
* ------------------------------------------------------------------------*/
static Void local checkSynonym(t) /* validate synonym definition */
Tycon t; {
List tvars = checkTypeLhs(tycon(t).line,fst(tycon(t).defn));
tycon(t).defn = checkDeclType(tycon(t).line,tvars,snd(tycon(t).defn));
}
static Void local checkData(t) /* validate datatype definition */
Tycon t; {
List tvars = checkTypeLhs(tycon(t).line,fst(tycon(t).defn));
Int constrNo = 0;
List cs = snd(tycon(t).defn);
Int arity = length(tvars);
Cell lhs = t;
Int i;
for (i=0; i<arity; ++i)
lhs = ap(lhs,mkOffset(i));
for (constrNo=0; nonNull(cs); cs=tl(cs))
hd(cs) = makeConstr(hd(cs),lhs,tvars,constrNo++,tycon(t).line);
}
static List local checkTypeLhs(line,lhs)/* check type on lhs of type defn */
Int line;
Cell lhs; {
List tvars = getArgs(lhs);
Cell temp = varFindDup(tvars);
if (nonNull(temp)) {
ERROR(line) "Repeated type variable \"%s\" on left hand side",
textToStr(textOf(temp))
EEND;
}
return tvars;
}
static Cell local varFindDup(xs) /* look for duplicates in var list */
List xs; {
for (; nonNull(xs); xs=tl(xs))
if (nonNull(varIsMember(textOf(hd(xs)),tl(xs))))
return hd(xs);
return NIL;
}
static Cell local checkDeclType(line,tvars,type)
Int line; /* validate declared type expr */
Cell type;
List tvars; {
Int arity = 0;
Cell t = type;
Cell p = NIL;
if (isVar(type)) {
t = findOffset(textOf(type),tvars);
if (isNull(t)) {
ERROR(line) "Undefined type variable \"%s\"",
textToStr(textOf(type))
EEND;
}
return t;
}
while (isAp(t)) {
arg(t) = checkDeclType(line,tvars,arg(t));
p = t;
t = fun(t);
arity++;
}
if (isCon(t)) {
Tycon tc = findTycon(textOf(t));
if (isNull(tc)) {
ERROR(line) "Undefined type constructor \"%s\"",
textToStr(textOf(t))
EEND;
}
if (tycon(tc).arity != arity) {
ERROR(line) "Wrong number of arguments for \"%s\"",
textToStr(textOf(t))
EEND;
}
if (nonNull(p)) fun(p)=tc; else return tc;
}
return type;
}
static Cell local findOffset(t,tvars) /* translate variable t into offset */
Text t; /* using list of variables tvars */
List tvars; {
Int offset;
for (offset=0; nonNull(tvars); offset++) {
if (t==textOf(hd(tvars)))
return mkOffset(offset);
tvars = tl(tvars);
}
return NIL;
}
static Name local makeConstr(c,type,tvars,constrNo,line) /* make constr fun*/
Cell c; /* constructor definition */
Cell type; /* left hand side of decl (used to construct type) */
List tvars; /* list of (distinct) bound variables on lhs of defn */
Int constrNo; /* constructor number (determines default order relation) */
Int line; { /* line number of definition */
Cell t;
Int arity;
Name n;
for (arity=0; isAp(c); arity++) {
t = fun(c);
arg(c) = checkDeclType(line,tvars,arg(c));
fun(c) = ARROW;
type = ap(c,type);
c = t;
}
n = findName(textOf(c));
if (isNull(n))
n = newName(textOf(c));
else if (name(n).defn!=PREDEFINED) {
ERROR(line) "Repeated definition for constructor function \"%s\"",
textToStr(name(n).text)
EEND;
}
name(n).line = line;
name(n).arity = arity;
name(n).number = constrNo;
name(n).type = (nonNull(tvars)?pair(mkInt(length(tvars)),type):type);
name(n).defn = CFUN;
return n;
}
/* --------------------------------------------------------------------------
* Calculate rank of type constructors in order to detect recursive and
* mutually recursive type synonym declarations.
* ------------------------------------------------------------------------*/
static Int local maximum(x,y) /* integer maximum */
Int x, y; {
return (x>y) ? x : y;
}
static Int local tyconRank(t) /* calculate rank of type constr */
Tycon t; {
switch (tycon(t).rank) {
case RANKVISITING : ERROR(tycon(t).line)
"Recursive type synonym \"%s\"",
textToStr(tycon(t).text)
EEND;
break;
case RANKUNKNOWN : tycon(t).rank = RANKVISITING;
tycon(t).rank = 1 + maxRank(tycon(t).defn);
tycon(t).defn = fullExpand(tycon(t).defn);
break;
}
return tycon(t).rank;
}
static Int local maxRank(t) /* calculate maximum rank of type */
Cell t; { /* synonym constructors in type expr*/
Int highest = 0;
for (highest=0; isAp(t); t=fun(t))
highest = maximum(highest,maxRank(arg(t)));
if (isTycon(t))
highest = maximum(highest,tyconRank(t));
return highest;
}
static Type local fullExpand(t) /* find full expansion of type exp */
Type t; { /* assuming that all relevant */
Cell h = t; /* synonym defns of lower rank have*/
for (; isAp(h); h=fun(h)) /* already been fully expanded */
arg(h) = fullExpand(arg(h));
if (isSynonym(h))
t = instantiateSyn(tycon(h).defn,t);
return t;
}
static Type local instantiateSyn(t,env) /* instantiate type according using*/
Type t; /* env to determine appropriate */
Type env; { /* values for OFFSET type vars */
switch (whatIs(t)) {
case AP : return ap(instantiateSyn(fun(t),env),
instantiateSyn(arg(t),env));
case OFFSET : return nthArg(offsetOf(t),env);
default : return t;
}
}
/* --------------------------------------------------------------------------
* Type expressions appearing in type signature declarations and expressions
* also require static checking, but unlike type expressions in type decls,
* they may introduce arbitrary new type variables. The static analysis
* required here is:
* - ensure that each type constructor is defined and used with the
* correct number of arguments.
*
* - replace type variables by offsets, constructor names by Tycons.
* ------------------------------------------------------------------------*/
static List local typeVarsIn(type,vs) /* calculate list of type variables */
Cell type; /* used in type expression, reading */
List vs; { /* from left to right */
switch (whatIs(type)) {
case AP : return typeVarsIn(snd(type),
typeVarsIn(fst(type),
vs));
case VARIDCELL :
case VAROPCELL : return maybeAppendVar(type,vs);
case QUAL : { List qs = fst(snd(type));
for (; nonNull(qs); qs=tl(qs))
vs = typeVarsIn(hd(qs),vs);
return typeVarsIn(snd(snd(type)),vs);
}
}
return vs;
}
static List local maybeAppendVar(v,vs) /* append variable to list if not */
Cell v; /* already included */
List vs; {
Text t = textOf(v);
List p = NIL;
List c = vs;
while (nonNull(c)) {
if (textOf(hd(c))==t)
return vs;
p = c;
c = tl(c);
}
if (nonNull(p))
tl(p) = cons(v,NIL);
else
vs = cons(v,NIL);
return vs;
}
static Cell local checkSigType(line,where,e,type)
Int line; /* check validity of type expression*/
String where; /* in explicit type signature */
Cell e;
Type type; {
List tvars = typeVarsIn(type,NIL);
Int n = length(tvars);
if (whatIs(type)==QUAL) {
map2Proc(checkClassConstraint,line,tvars,fst(snd(type)));
snd(snd(type)) = checkDeclType(line,tvars,snd(snd(type)));
if (isAmbiguous(type))
ambigError(line,where,e,type);
}
else
type = checkDeclType(line,tvars,type);
return n>0 ? pair(mkInt(n),type) : type;
}
static Void local checkClassConstraint(line,tvars,cl)
Int line; /* check class constraint in type...*/
List tvars;
Cell cl; {
Int args = 0;
Cell prev = NIL;
Cell temp = cl;
do { /* parser ensures no. args >= 1 */
arg(temp) = checkDeclType(line,tvars,arg(temp));
prev = temp;
temp = fun(temp);
args++;
} while (isAp(temp));
fun(prev) = classDefined(line,temp);
if (args!=class(fun(prev)).arity) {
ERROR(line) "Wrong number of arguments for class \"%s\"",
textToStr(class(fun(prev)).text)
EEND;
}
}
static Class local classDefined(line,cv)
Int line; /* check that class name is defined */
Cell cv; { /* cv :: CONIDCELL */
Class c = findClass(textOf(cv));
if (isNull(c)) {
ERROR(line) "Undefined class \"%s\"", textToStr(textOf(cv))
EEND;
}
return c;
}
/* --------------------------------------------------------------------------
* Check for ambiguous types:
* A type Preds => type is ambiguous if not (TV(P) `subset` TV(type))
* ------------------------------------------------------------------------*/
static List local offsetTyvarsIn(t,vs) /* add list of offset tyvars in t */
Type t; /* to list vs */
List vs; {
switch (whatIs(t)) {
case AP : return offsetTyvarsIn(fun(t),offsetTyvarsIn(snd(t),vs));
case OFFSET : if (cellIsMember(t,vs))
return vs;
else
return cons(t,vs);
case QUAL : return offsetTyvarsIn(snd(t),vs);
default : return vs;
}
}
Bool isAmbiguous(type) /* Determine whether type is */
Type type; { /* ambiguous */
if (isPolyType(type))
type = snd(type);
if (whatIs(type)==QUAL) { /* only qualified types can be */
List tvps = offsetTyvarsIn(fst(snd(type)),NIL); /* ambiguous */
List tvts = offsetTyvarsIn(snd(snd(type)),NIL);
while (nonNull(tvps) && cellIsMember(hd(tvps),tvts))
tvps = tl(tvps);
return nonNull(tvps);
}
return FALSE;
}
Void ambigError(line,where,e,type) /* produce error message for */
Int line; /* ambiguity */
String where;
Cell e;
Type type; {
ERROR(line) "Ambiguous type signature in %s", where ETHEN
ERRTEXT "\n*** ambiguous type : " ETHEN ERRTYPE(type);
ERRTEXT "\n*** assigned to : " ETHEN ERREXPR(e);
ERRTEXT "\n"
EEND;
}
/* --------------------------------------------------------------------------
* Static analysis of class declarations:
*
* Performed in a similar manner to that used for type declarations.
*
* The first part of the static analysis is performed as the declarations
* are read during parsing:
* - no previous definition for class
* - class name not previously used as a type constructor
* - make new entry in class table
* - determine arity of class
* - record line number of declaration
* - build list of classes defined in current script for use in later
* stages of static analysis.
* ------------------------------------------------------------------------*/
Void classDefn(line,head,ms) /* process new class definition */
Int line; /* definition line number */
Cell head; /* class header :: ([Supers],Class) */
List ms; { /* class definition body */
Text ct = textOf(getHead(snd(head)));
Int arity = argCount;
Class new = findClass(ct);
if (isNull(new)) {
if (nonNull(findTycon(ct))) {
ERROR(line) "\"%s\" used as both class and type constructor",
textToStr(ct)
EEND;
}
new = newClass(ct);
}
else if (class(new).head!=PREDEFINED) {
ERROR(line) "Repeated definition of type class \"%s\"",
textToStr(ct)
EEND;
}
class(new).arity = arity;
class(new).line = line;
class(new).head = snd(head);
class(new).supers = fst(head);
class(new).members = ms;
classDefns = cons(new,classDefns);
}
/* --------------------------------------------------------------------------
* Further analysis of class declarations:
*
* Full static analysis of class definitions must be postponed until the
* complete script has been read and all static analysis on type definitions
* has been completed.
*
* Once this has been achieved, we carry out the following checks on each
* class definition:
*
* - each named superclass has been defined
* - replace class(...).supers with a list of superclass skeletons
*
* - split body of class into members and declarations
* - make new name entry for each member function
* - record member function number (eventually an offset into dictionary!)
* - no member function has a previous definition ...
* - no member function is mentioned more than once in the list of members
* - each member function type is valid, replace vars by offsets
* - qualify each member function type by class header
* - only bindings for members appear in defaults
* - only function bindings appear in defaults
* ------------------------------------------------------------------------*/
static Void local checkClassDefn(c) /* validate class definition */
Class c; {
List tvars = NIL;
Int args = 0;
Int i;
Cell temp;
/* build list of type variables in class header */
for (temp=class(c).head; isAp(temp); temp=fun(temp)) {
if (!isVar(arg(temp))) {
ERROR(class(c).line) "Type variable required in class header"
EEND;
}
if (nonNull(varIsMember(textOf(arg(temp)),tvars))) {
ERROR(class(c).line)
"Repeated type variable \"%s\" in class header",
textToStr(textOf(arg(temp)))
EEND;
}
tvars = cons(arg(temp),tvars);
args++;
}
for (temp=class(c).head, i=args-1; i>0; temp=fun(temp), i--)
arg(temp) = mkOffset(i);
arg(temp) = mkOffset(0);
fun(temp) = c;
map2Proc(checkClassConstraint,class(c).line,tvars,class(c).supers);
class(c).numSupers = length(class(c).supers);
temp = extractBindings(class(c).members);
class(c).members = addMemberFunctions(c,
tvars,
extractSigdecls(class(c).members));
class(c).numMembers = length(class(c).members);
class(c).defaults = classBindings("class",c,temp);
}
static List local addMemberFunctions(c,tvars,ms)
Class c;
List tvars;
List ms; { /* :: [ (Line,[Var],type) ] */
List mfuns = NIL; /* List of member functions */
Int mno = 1; /* Member function number */
List qs = cons(class(c).head,NIL);
for (; nonNull(ms); ms=tl(ms)) { /* cycle through each sigdecl */
Int line = intOf(fst3(hd(ms)));
List vs = snd3(hd(ms));
Type t = thd3(hd(ms));
tvars = typeVarsIn(t,tvars);
t = pair(mkInt(length(tvars)),
ap(QUAL,pair(qs,
checkDeclType(line,tvars,t))));
if (isAmbiguous(t))
ambigError(line,"class declaration",hd(vs),t);
for (; nonNull(vs); vs=tl(vs))
mfuns = cons(newMember(line,hd(vs),mno++,t),mfuns);
tvars = take(class(c).arity,tvars); /* delete additional tvars */
}
return rev(mfuns);
}
static Name local newMember(line,v,no,t)
Int line;
Cell v;
Int no;
Type t; {
Name m = findName(textOf(v));
if (isNull(m))
m = newName(textOf(v));
else if (name(m).defn!=PREDEFINED) {
ERROR(line) "Repeated definition for member function \"%s\"",
textToStr(name(m).text)
EEND;
}
name(m).line = line;
name(m).arity = 1;
name(m).number = no;
name(m).type = t;
name(m).defn = MFUN;
return m;
}
/* --------------------------------------------------------------------------
* Static analysis of instance declarations:
*
* The first part of the static analysis is performed as the declarations
* are read during parsing:
* - make new entry in instance table
* - record line number of declaration
* - build list of instances defined in current script for use in later
* stages of static analysis.
* ------------------------------------------------------------------------*/
Void instDefn(line,head,ms) /* process new instance definition */
Int line; /* definition line number */
Cell head; /* inst header :: (context,Class) */
List ms; { /* instance members */
Inst new = newInst();
inst(new).line = line;
inst(new).specifics = fst(head);
inst(new).head = snd(head);
inst(new).implements = ms;
instDefns = cons(new,instDefns);
}
/* --------------------------------------------------------------------------
* Further static analysis of instance declarations:
*
* Makes the following checks:
* - Class part of header is a valid class expression C t1 ... tn not
* overlapping with any other instance in class C.
* - Each element of context is a valid class expression, with type vars
* drawn from the types t1,...,tn.
* - replace type vars in class header by offsets, validate all types etc.
* - All bindings are function bindings
* - All bindings define member functions for class C
* - Arrange bindings into appropriate order for member list
* - No top level type signature declarations
* ------------------------------------------------------------------------*/
static Void local checkInstDefn(in) /* validate instance declaration */
Inst in; {
Int line = inst(in).line;
List tvars = typeVarsIn(inst(in).head,NIL);
List ins;
checkClassConstraint(line,tvars,inst(in).head);
map2Proc(checkClassConstraint,line,tvars,inst(in).specifics);
inst(in).cl = getHead(inst(in).head);
inst(in).freedom = length(tvars);
for (ins=class(inst(in).cl).instances; nonNull(ins); ins=tl(ins)) {
Cell pi = instsOverlap(in,hd(ins));
if (nonNull(pi)) {
ERROR(line) "Overlapping instances for class \"%s\"",
textToStr(class(inst(in).cl).text)
ETHEN
ERRTEXT "\n*** This instance : " ETHEN ERRPRED(inst(in).head);
ERRTEXT "\n*** Overlaps with : " ETHEN
ERRPRED(inst(hd(ins)).head);
ERRTEXT "\n*** Common instance : " ETHEN
ERRPRED(pi);
ERRTEXT "\n"
EEND;
}
}
class(inst(in).cl).instances
= cons(in,class(inst(in).cl).instances);
inst(in).numSpecifics = length(inst(in).specifics);
if (nonNull(extractSigdecls(inst(in).implements))) {
ERROR(line) "Type signature decls not permitted in instance decl"
EEND;
}
inst(in).implements = classBindings("instance",
inst(in).cl,
extractBindings(inst(in).implements));
}
/* --------------------------------------------------------------------------
* Process class and instance declaration binding groups:
* ------------------------------------------------------------------------*/
static List local classBindings(where,c,bs)
String where; /* check validity of bindings bs for*/
Class c; /* class c (or an instance of c) */
List bs; { /* sort into approp. member order */
List nbs = NIL;
for (; nonNull(bs); bs=tl(bs)) {
Cell b = hd(bs);
Name nm = newName(inventText()); /* pick name for implementation */
Int mno;
if (!isVar(fst(b))) { /* only allows function bindings */
ERROR(rhsLine(snd(snd(snd(b)))))
"Pattern binding illegal in %s declaration", where
EEND;
}
mno = memberNumber(c,textOf(fst(b)));
if (mno==0) {
ERROR(rhsLine(snd(hd(snd(snd(b))))))
"No member \"%s\" in class \"%s\"",
textToStr(textOf(fst(b))),
textToStr(class(c).text)
EEND;
}
name(nm).defn = snd(snd(b)); /* save definition of implementation*/
nbs = numInsert(mno-1,nm,nbs);
}
return nbs;
}
static Int local memberNumber(c,t) /* return number of member function */
Class c; /* with name t in class c */
Text t; { /* return 0 if not a member */
List ms = class(c).members;
for (; nonNull(ms); ms=tl(ms))
if (t==name(hd(ms)).text)
return name(hd(ms)).number;
return 0;
}
static List local numInsert(n,x,xs) /* insert x at nth position in xs, */
Int n; /* filling gaps with NIL */
Cell x;
List xs; {
List start = isNull(xs) ? cons(NIL,NIL) : xs;
for (xs=start; 0<n--; xs=tl(xs))
if (isNull(tl(xs)))
tl(xs) = cons(NIL,NIL);
hd(xs) = x;
return start;
}
/* --------------------------------------------------------------------------
* Primitive definitions are usually only included in the first script
* file read - the prelude. A primitive definition associates a variable
* name with a string (which identifies a built-in primitive) and a type.
* ------------------------------------------------------------------------*/
Void primDefn(line,prims,type) /* Handle primitive definitions */
Int line;
List prims;
Cell type; {
type = checkSigType(line,"primitive",fst(hd(prims)),type);
for (; nonNull(prims); prims=tl(prims))
addNewPrim(line,
textOf(fst(hd(prims))),
textToStr(textOf(snd(hd(prims)))),
type);
}
static Void local addNewPrim(l,vn,s,t) /* make binding of variable vn to */
Int l; /* primitive function referred */
Text vn; /* to by s, with given type t */
String s; /* return TRUE if vn already bound */
Cell t;{
Name n = findName(vn);
Int i;
if (isNull(n))
n = newName(vn);
else if (name(n).defn!=PREDEFINED) {
ERROR(l) "Redeclaration of primitive \"%s\"", textToStr(vn)
EEND;
}
name(n).line = l;
for (i=0; primitives[i].ref; ++i)
if (strcmp(s,primitives[i].ref)==0) {
addPrim(n,primitives[i].arity,t,primitives[i].imp);
return;
}
ERROR(l) "Unknown primitive reference \"%s\"", s
EEND;
}
/* --------------------------------------------------------------------------
* Static analysis of patterns:
*
* Patterns are parsed as ordinary (atomic) expressions. Static analysis
* makes the following checks:
* - Patterns are well formed (according to pattern syntax), including the
* special case of (n+k) patterns.
* - All constructor functions have been defined and are used with the
* correct number of arguments.
* - No variable name is used more than once in a pattern.
*
* The list of pattern variables occuring in each pattern is accumulated in
* a global list `patVars', which must be initialised to NIL at appropriate
* points before using these routines to check for valid patterns. This
* mechanism enables the pattern checking routine to be mapped over a list
* of patterns, ensuring that no variable occurs more than once in the
* complete pattern list (as is required on the lhs of a function defn).
* ------------------------------------------------------------------------*/
static List patVars; /* list of vars bound in pattern */
static Cell local checkPat(line,p) /* Check valid pattern syntax */
Int line;
Cell p; {
switch (whatIs(p)) {
case VARIDCELL :
case VAROPCELL : addPatVar(line,p);
break;
case AP : return checkMaybeCnkPat(line,p);
case NAME :
case CONIDCELL :
case CONOPCELL : return checkApPat(line,0,p);
case UNIT :
case WILDCARD :
case STRCELL :
case CHARCELL :
case INTCELL : break;
case ASPAT : addPatVar(line,fst(snd(p)));
snd(snd(p)) = checkPat(line,snd(snd(p)));
break;
case LAZYPAT : snd(p) = checkPat(line,snd(p));
break;
case FINLIST : map1Over(checkPat,line,snd(p));
break;
default : ERROR(line) "Illegal pattern syntax"
EEND;
}
return p;
}
static Cell local checkMaybeCnkPat(l,p)/* Check applicative pattern with */
Int l; /* the possibility of c*n or n+k */
Cell p; { /* pattern */
Text t = textOf(getHead(p));
if (argCount==2 && t==textPlus) { /* n+k pattern */
Cell v = arg(fun(p));
if (!isInt(arg(p))) {
ERROR(l) "Second argument in (n+k) pattern must be an integer"
EEND;
}
if (intOf(arg(p))<=0) {
ERROR(l) "Integer k in (n+k) pattern must be > 0"
EEND;
}
fst(fun(p)) = ADDPAT;
intValOf(fun(p)) = intOf(arg(p));
arg(p) = checkPat(l,v);
return p;
}
if (argCount==2 && t==textMult) { /* c*n pattern */
if (!isInt(arg(fun(p)))) {
ERROR(l) "First argument in (c*n) pattern must be an integer"
EEND;
}
if (intOf(arg(fun(p)))<=1) {
ERROR(l) "Integer c in (c*n) pattern must be > 1"
EEND;
}
fst(fun(p)) = MULPAT;
intValOf(fun(p)) = intOf(arg(fun(p)));
arg(p) = checkPat(l,arg(p));
return p;
}
return checkApPat(l,0,p);
}
static Cell local checkApPat(line,args,p)
Int line; /* check validity of application */
Int args; /* of constructor to arguments */
Cell p; {
switch (whatIs(p)) {
case AP : fun(p) = checkApPat(line,args+1,fun(p));
arg(p) = checkPat(line,arg(p));
break;
case TUPLE : if (tupleOf(p)!=args)
internal("bad pattern tuple");
break;
case CONIDCELL :
case CONOPCELL : p = conDefined(line,textOf(p));
checkCfunArgs(line,p,args);
break;
case NAME : checkIsCfun(line,p);
checkCfunArgs(line,p,args);
break;
default : ERROR(line) "Illegal pattern syntax"
EEND;
}
return p;
}
static Void local addPatVar(line,v) /* add variable v to list of vars */
Int line; /* in current pattern, checking for */
Cell v; { /* repeated variables. */
Text t = textOf(v);
List p = NIL;
List n = patVars;
for (; nonNull(n); p=n, n=tl(n))
if (textOf(hd(n))==t) {
ERROR(line) "Repeated variable \"%s\" in pattern",
textToStr(t)
EEND;
}
if (isNull(p))
patVars = cons(v,NIL);
else
tl(p) = cons(v,NIL);
}
static Name local conDefined(line,t) /* check that t is the name of a */
Int line; /* previously defined constructor */
Text t; { /* function. */
Cell c=findName(t);
if (isNull(c)) {
ERROR(line) "Undefined constructor function \"%s\"", textToStr(t)
EEND;
}
checkIsCfun(line,c);
return c;
}
static Void local checkIsCfun(line,c) /* Check that c is a constructor fn */
Int line;
Cell c; {
if (name(c).defn!=CFUN) {
ERROR(line) "\"%s\" is not a constructor function",
textToStr(name(c).text)
EEND;
}
}
static Void local checkCfunArgs(line,c,args)
Int line; /* Check constructor applied with */
Cell c; /* correct number of arguments */
Int args; {
if (name(c).arity!=args) {
ERROR(line) "Constructor function \"%s\" needs %d args in pattern",
textToStr(name(c).text), name(c).arity
EEND;
}
}
/* --------------------------------------------------------------------------
* Maintaining lists of bound variables and local definitions, for
* dependency and scope analysis.
* ------------------------------------------------------------------------*/
static List bounds; /* list of lists of bound vars */
static List bindings; /* list of lists of binds in scope */
static List depends; /* list of lists of dependents */
#define saveBvars() hd(bounds) /* list of bvars in current scope */
#define restoreBvars(bs) hd(bounds)=bs /* restore list of bound variables */
static Cell local bindPat(line,p) /* add new bound vars for pattern */
Int line;
Cell p; {
patVars = NIL;
p = checkPat(line,p);
hd(bounds) = revOnto(patVars,hd(bounds));
return p;
}
static Void local bindPats(line,ps) /* add new bound vars for patterns */
Int line;
List ps; {
patVars = NIL;
map1Over(checkPat,line,ps);
hd(bounds) = revOnto(patVars,hd(bounds));
}
/* --------------------------------------------------------------------------
* Before processing value and type signature declarations, all data and
* type definitions have been processed so that:
* - all valid type constructors (with their arities) are known.
* - all valid constructor functions (with their arities and types) are
* known.
*
* The result of parsing a list of value declarations is a list of Eqns:
* Eqn ::= (SIGDECL,(Line,[Var],type)) | (Expr,Rhs)
* The ordering of the equations in this list is the reverse of the original
* ordering in the script parsed. This is a consequence of the structure of
* the parser ... but also turns out to be most convenient for the static
* analysis.
*
* As the first stage of the static analysis of value declarations, each
* list of Eqns is converted to a list of Bindings. As part of this
* process:
* - The ordering of the list of Bindings produced is the same as in the
* original script.
* - When a variable (function) is defined over a number of lines, all
* of the definitions should appear together and each should give the
* same arity to the variable being defined.
* - No variable can have more than one definition.
* - For pattern bindings:
* - Each lhs is a valid pattern/function lhs, all constructor functions
* have been defined and are used with the correct number of arguments.
* - Each lhs contains no repeated pattern variables.
* - Each equation defines at least one variable (e.g. True = False is
* not allowed).
* - Types appearing in type signatures are well formed:
* - Type constructors used are defined and used with correct number
* of arguments.
* - type variables are replaced by offsets, type constructor names
* by Tycons.
* - Every variable named in a type signature declaration is defined by
* one or more equations elsewhere in the script.
* - No variable has more than one type declaration.
*
* ------------------------------------------------------------------------*/
#define bindingType(b) fst(snd(b)) /* type (or types) for binding */
#define fbindAlts(b) snd(snd(b)) /* alternatives for function binding*/
static List local extractSigdecls(es) /* extract the SIGDECLS from list */
List es; { /* of equations */
List sigDecls = NIL; /* :: [(Line,[Var],Type)] */
for(; nonNull(es); es=tl(es))
if (fst(hd(es))==SIGDECL) /* type-declaration? */
sigDecls = cons(snd(hd(es)),sigDecls); /* discard SIGDECL tag*/
return sigDecls;
}
static List local extractBindings(es) /* extract untyped bindings from */
List es; { /* given list of equations */
Cell lastVar = NIL; /* = var def'd in last eqn (if any) */
Int lastArity = 0; /* = number of args in last defn */
List bs = NIL; /* :: [Binding] */
for(; nonNull(es); es=tl(es)) {
Cell e = hd(es);
if (fst(e)!=SIGDECL) {
Int line = rhsLine(snd(e));
Cell lhsHead = getHead(fst(e));
switch (whatIs(lhsHead)) {
case VARIDCELL :
case VAROPCELL : { /* function-binding? */
Cell newAlt = pair(getArgs(fst(e)), snd(e));
if (nonNull(lastVar) && textOf(lhsHead)==textOf(lastVar)) {
if (argCount!=lastArity) {
ERROR(line)
"Equations give different arities for \"%s\"",
textToStr(textOf(lhsHead))
EEND;
}
fbindAlts(hd(bs)) = cons(newAlt,fbindAlts(hd(bs)));
}
else {
lastVar = lhsHead;
lastArity = argCount;
notDefined(line,bs,lhsHead);
bs = cons(pair(lhsHead,
pair(NIL,
singleton(newAlt))),
bs);
}
}
break;
case CONOPCELL :
case CONIDCELL :
case FINLIST :
case TUPLE :
case UNIT :
case ASPAT : lastVar = NIL; /* pattern-binding? */
patVars = NIL;
fst(e) = checkPat(line,fst(e));
if (isNull(patVars)) {
ERROR(line)
"No variables defined in lhs pattern"
EEND;
}
map2Proc(notDefined,line,bs,patVars);
bs = cons(pair(patVars,pair(NIL,e)),bs);
break;
default : ERROR(line) "Improper left hand side"
EEND;
}
}
}
return bs;
}
static List local eqnsToBindings(es) /* Convert list of equations to list*/
List es; { /* of typed bindings */
List bs = extractBindings(es);
map1Proc(addSigDecl,bs,extractSigdecls(es));
return bs;
}
static Void local notDefined(line,bs,v)/* check if name already defined in */
Int line; /* list of bindings */
List bs;
Cell v; {
if (nonNull(findBinding(textOf(v),bs))) {
ERROR(line) "\"%s\" multiply defined", textToStr(textOf(v))
EEND;
}
}
static Cell local findBinding(t,bs) /* look for binding for variable t */
Text t; /* in list of bindings bs */
List bs; {
for (; nonNull(bs); bs=tl(bs))
if (isVar(fst(hd(bs)))) { /* function-binding? */
if (textOf(fst(hd(bs)))==t)
return hd(bs);
}
else if (nonNull(varIsMember(t,fst(hd(bs))))) /* pattern-binding? */
return hd(bs);
return NIL;
}
static Void local addSigDecl(bs,sigDecl)/* add type information to bindings*/
List bs; /* :: [Binding] */
Cell sigDecl; { /* :: (Line,[Var],Type) */
Int line = intOf(fst3(sigDecl));
Cell vs = snd3(sigDecl);
Cell type = checkSigType(line,"type declaration",hd(vs),thd3(sigDecl));
map3Proc(setType,line,type,bs,vs);
}
static Void local setType(line,type,bs,v)
Int line; /* Set type of variable */
Cell type;
Cell v;
List bs; {
Text t = textOf(v);
Cell b = findBinding(t,bs);
if (isNull(b)) {
ERROR(line) "Type declaration for variable \"%s\" with no body",
textToStr(t)
EEND;
}
if (isVar(fst(b))) { /* function-binding? */
if (isNull(bindingType(b))) {
bindingType(b) = type;
return;
}
}
else { /* pattern-binding? */
List vs = fst(b);
List ts = bindingType(b);
if (isNull(ts))
bindingType(b) = ts = copy(length(vs),NIL);
while (nonNull(vs) && t!=textOf(hd(vs))) {
vs = tl(vs);
ts = tl(ts);
}
if (nonNull(vs) && isNull(hd(ts))) {
hd(ts) = type;
return;
}
}
ERROR(line) "Repeated type declaration for \"%s\"", textToStr(t)
EEND;
}
/* --------------------------------------------------------------------------
* To facilitate dependency analysis, lists of bindings are temporarily
* augmented with an additional field, which is used in two ways:
* - to build the `adjacency lists' for the dependency graph. Represented by
* a list of pointers to other bindings in the same list of bindings.
* - to hold strictly positive integer values (depth first search numbers) of
* elements `on the stack' during the strongly connected components search
* algorithm, or a special value mkInt(0), once the binding has been added
* to a particular strongly connected component.
*
* Using this extra field, the type of each list of declarations during
* dependency analysis is [Binding'] where:
*
* Binding' ::= (Var, (Dep, (Type, [Alt]))) -- function binding
* | ([Var], (Dep, (Type, (Pat,Rhs)))) -- pattern binding
*
* ------------------------------------------------------------------------*/
#define depVal(d) (fst(snd(d))) /* Access to dependency information */
static List local dependencyAnal(bs) /* Separate lists of bindings into */
List bs; { /* mutually recursive groups in */
/* order of dependency */
mapProc(addDepField,bs); /* add extra field for dependents */
mapProc(depBinding,bs); /* find dependents of each binding */
bs = scc(bs); /* sort to strongly connected comps */
mapProc(remDepField,bs); /* remove dependency info field */
return bs;
}
static List local topDependAnal(bs) /* Like dependencyAnal(), but at */
List bs; { /* top level, reporting on progress */
List xs;
Int i = 0;
setGoal("Dependency analysis",(Target)(length(bs)));
mapProc(addDepField,bs); /* add extra field for dependents */
for (xs=bs; nonNull(xs); xs=tl(xs)) {
depBinding(hd(xs));
soFar((Target)(i++));
}
bs = scc(bs); /* sort to strongly connected comps */
mapProc(remDepField,bs); /* remove dependency info field */
done();
return bs;
}
static Void local addDepField(b) /* add extra field to binding to */
Cell b; { /* hold list of dependents */
snd(b) = pair(NIL,snd(b));
}
static Void local remDepField(bs) /* remove dependency field from */
List bs; { /* list of bindings */
mapProc(remDepField1,bs);
}
static Void local remDepField1(b) /* remove dependency field from */
Cell b; { /* single binding */
snd(b) = snd(snd(b));
}
static Void local clearScope() { /* initialise dependency scoping */
bounds = NIL;
bindings = NIL;
depends = NIL;
}
static Void local withinScope(bs) /* enter scope of bindings bs */
List bs; {
bounds = cons(NIL,bounds);
bindings = cons(bs,bindings);
depends = cons(NIL,depends);
}
static Void local leaveScope() { /* leave scope of last withinScope */
bounds = tl(bounds);
bindings = tl(bindings);
depends = tl(depends);
}
/* --------------------------------------------------------------------------
* As a side effect of the dependency analysis we also make the following
* checks:
* - Each lhs is a valid pattern/function lhs, all constructor functions
* have been defined and are used with the correct number of arguments.
* - No lhs contains repeated pattern variables.
* - Expressions used on the rhs of an eqn should be well formed. This
* includes:
* - Checking for valid patterns (including repeated vars) in lambda,
* case, and list comprehension expressions.
* - Recursively checking local lists of equations.
* - No free (i.e. unbound) variables are used in the declaration list.
* ------------------------------------------------------------------------*/
static Void local depBinding(b) /* find dependents of binding */
Cell b; {
Cell defpart = snd(snd(snd(b))); /* definition part of binding */
hd(depends) = NIL;
if (isVar(fst(b))) { /* function-binding? */
mapProc(depAlt,defpart);
}
else { /* pattern-binding? */
depRhs(snd(defpart));
}
depVal(b) = hd(depends);
}
static Void local depDefaults(c) /* dependency analysis on defaults */
Class c; { /* from class definition */
depClassBindings(class(c).defaults);
}
static Void local depInsts(in) /* dependency analysis on instance */
Inst in; { /* bindings */
depClassBindings(inst(in).implements);
}
static Void local depClassBindings(bs) /* dependency analysis on list of */
List bs; { /* bindings, possibly containing */
for (; nonNull(bs); bs=tl(bs)) /* NIL bindings ... */
if (nonNull(hd(bs))) /* No need to add extra field for */
mapProc(depAlt,name(hd(bs)).defn); /* dependency information.. */
}
static Void local depAlt(a) /* find dependents of alternative */
Cell a; {
List origBvars = saveBvars(); /* save list of bound variables */
bindPats(rhsLine(snd(a)),fst(a)); /* add new bound vars for patterns */
depRhs(snd(a)); /* find dependents of rhs */
restoreBvars(origBvars); /* restore original list of bvars */
}
static Void local depRhs(r) /* find dependents of rhs */
Cell r; {
switch (whatIs(r)) {
case GUARDED : mapProc(depGuard,snd(r));
break;
case LETREC : fst(snd(r)) = eqnsToBindings(fst(snd(r)));
withinScope(fst(snd(r)));
fst(snd(r)) = dependencyAnal(fst(snd(r)));
hd(depends) = fst(snd(r));
depRhs(snd(snd(r)));
leaveScope();
break;
default : snd(r) = depExpr(intOf(fst(r)),snd(r));
break;
}
}
static Void local depGuard(g) /* find dependents of single guarded*/
Cell g; { /* expression */
depPair(intOf(fst(g)),snd(g));
}
static Cell local depExpr(line,e) /* find dependents of expression */
Int line;
Cell e; {
switch (whatIs(e)) {
case VARIDCELL :
case VAROPCELL : return depVar(line,e);
case CONIDCELL :
case CONOPCELL : return conDefined(line,textOf(e));
case AP : depPair(line,e);
break;
case NAME :
case UNIT :
case TUPLE :
case STRCELL :
case CHARCELL :
case FLOATCELL :
case INTCELL : break;
case COND : depTriple(line,snd(e));
break;
case FINLIST : map1Over(depExpr,line,snd(e));
break;
case LETREC : fst(snd(e)) = eqnsToBindings(fst(snd(e)));
withinScope(fst(snd(e)));
fst(snd(e)) = dependencyAnal(fst(snd(e)));
hd(depends) = fst(snd(e));
snd(snd(e)) = depExpr(line,snd(snd(e)));
leaveScope();
break;
case LAMBDA : depAlt(snd(e));
break;
case LISTCOMP : depListComp(line,snd(e));
break;
case ESIGN : fst(snd(e)) = depExpr(line,fst(snd(e)));
snd(snd(e)) = checkSigType(line,
"expression",
fst(snd(e)),
snd(snd(e)));
break;
case CASE : fst(snd(e)) = depExpr(line,fst(snd(e)));
map1Proc(depCaseAlt,line,snd(snd(e)));
break;
case ASPAT : ERROR(line) "Illegal `@' in expression"
EEND;
case LAZYPAT : ERROR(line) "Illegal `~' in expression"
EEND;
case WILDCARD : ERROR(line) "Illegal `_' in expression"
EEND;
default : internal("in depExpr");
}
return e;
}
static Void local depPair(line,e) /* find dependents of pair of exprs */
Int line;
Cell e; {
fst(e) = depExpr(line,fst(e));
snd(e) = depExpr(line,snd(e));
}
static Void local depTriple(line,e) /* find dependents of triple exprs */
Int line;
Cell e; {
fst3(e) = depExpr(line,fst3(e));
snd3(e) = depExpr(line,snd3(e));
thd3(e) = depExpr(line,thd3(e));
}
static Void local depListComp(line,e) /* find dependents of list compr. */
Int line;
Cell e; {
List origBvars = saveBvars(); /* save list of bound variables */
map1Proc(depQual,line,snd(e));
fst(e) = depExpr(line,fst(e));
restoreBvars(origBvars);
}
static Void local depQual(line,qual) /* find dependents of qualifier */
Int line;
Cell qual; {
switch(whatIs(qual)) {
case FROMQUAL : snd(snd(qual)) = depExpr(line,snd(snd(qual)));
fst(snd(qual)) = bindPat(line,fst(snd(qual)));
break;
case QWHERE : fst(snd(qual)) = bindPat(line,fst(snd(qual)));
snd(snd(qual)) = depExpr(line,snd(snd(qual)));
break;
case BOOLQUAL : snd(qual) = depExpr(line,snd(qual));
break;
}
}
static Void local depCaseAlt(line,a) /* find dependents of case altern. */
Int line;
Cell a; {
List origBvars = saveBvars(); /* save list of bound variables */
fst(a) = bindPat(line,fst(a)); /* add new bound vars for patterns */
depRhs(snd(a)); /* find dependents of rhs */
restoreBvars(origBvars); /* restore original list of bvars */
}
static Cell local depVar(line,e) /* register occurrence of variable */
Int line;
Cell e; {
List bounds1 = bounds;
List bindings1 = bindings;
List depends1 = depends;
Text t = textOf(e);
Cell n;
while (nonNull(bindings1)) {
n = varIsMember(t,hd(bounds1)); /* look for t in bound variables */
if (nonNull(n))
return n;
n = findBinding(t,hd(bindings1)); /* look for t in var bindings */
if (nonNull(n)) {
if (!cellIsMember(n,hd(depends1)))
hd(depends1) = cons(n,hd(depends1));
return (isVar(fst(n)) ? fst(n) : e);
}
bounds1 = tl(bounds1);
bindings1 = tl(bindings1);
depends1 = tl(depends1);
}
if (isNull(n=findName(t))) { /* check global definitions */
ERROR(line) "Undefined variable \"%s\"", textToStr(t)
EEND;
}
return n;
}
/* --------------------------------------------------------------------------
* Using the dependency graph for a list of bindings, we rearrange the list
* into groups of mutually recursive bindings, in order of dependency
* (no binding appears in the resulting list before its dependents in other
* groups of mutually recursive bindings). This is achieved using the
* standard algorithm described in:
* 1) Robert Tarjan, Depth-first search and Linear Graph Algorithms,
* SIAM J COMPUT, vol 1, no 2, June 1972, pp.146-160.
* 2) Aho, Hopcroft and Ullman, Design and Analysis of Algorithms,
* Addison Wesley, 1972. pp.189-195.
* The version used here probably owes most to the latter presentation but
* has been modified to simplify the algorithm and improve the use of space.
* ------------------------------------------------------------------------*/
#define visited(d) (isInt(depVal(d))) /* binding already visited ? */
static Cell daSccs = NIL;
static Int daCount;
static Int local sccMin(x,y) /* calculate minimum of x,y (unless */
Int x,y; { /* y is zero) */
return (x<=y || y==0) ? x : y;
}
static Int local lowlink(v) /* calculate `lowlink' of v */
Cell v; {
Int low = daCount;
Int dfn = daCount; /* depth first search no. of v */
List ws = depVal(v); /* adjacency list for v */
depVal(v) = mkInt(daCount++); /* push v onto stack */
push(v);
while (nonNull(ws)) { /* scan adjacency list for v */
Cell w = hd(ws);
ws = tl(ws);
low = sccMin(low, (visited(w) ? intOf(depVal(w)) : lowlink(w)));
}
if (low == dfn) { /* start a new scc? */
List temp=NIL;
do { /* take elements from stack */
depVal(top()) = mkInt(0);
temp = cons(top(),temp);
} while (pop()!=v);
daSccs = cons(temp,daSccs); /* make new strongly connected comp.*/
}
return low;
}
static List local scc(bs) /* sort list of bindings with added */
List bs; { /* dependency info into SCCs */
clearStack();
daSccs = NIL; /* clear current list of SCCs */
for (daCount=1; nonNull(bs); bs=tl(bs)) /* visit each binding */
if (!visited(hd(bs)))
lowlink(hd(bs));
return rev(daSccs); /* reverse to obtain correct order */
}
/* --------------------------------------------------------------------------
* Main static analysis:
* ------------------------------------------------------------------------*/
Void checkExp() { /* Top level static check on Expr */
staticAnalysis(RESET);
clearScope(); /* Analyse expression in the scope*/
withinScope(NIL); /* of no local bindings */
inputExpr = depExpr(0,inputExpr);
leaveScope();
staticAnalysis(RESET);
}
Void checkDefns() { /* Top level static analysis */
staticAnalysis(RESET);
mapProc(checkSynonym,synonymDefns); /* Check type synonym definitions */
mapProc(checkData,dataDefns); /* ... and data type definitions */
mapProc(tyconRank,synonymDefns); /* Calculate synonym ranks */
dataDefns = NIL; /* Discard lists of definitions */
synonymDefns = NIL;
mapProc(checkClassDefn,classDefns); /* Process class definitions */
mapProc(checkInstDefn,instDefns); /* Process instance definitions */
valDefns = eqnsToBindings(valDefns); /* translate value equations */
map1Proc(opDefined,valDefns,opDefns);/* check all declared ops bound */
mapProc(allNoPrevDef,valDefns); /* check against previous defns */
clearScope();
withinScope(valDefns);
valDefns = topDependAnal(valDefns); /* top level dependency ordering */
mapProc(depDefaults,classDefns); /* dep. analysis on class defaults*/
mapProc(depInsts,instDefns); /* dep. analysis on inst defns */
leaveScope();
staticAnalysis(RESET);
}
static Void local opDefined(bs,op) /* check that op bound in bs */
List bs; /* (or in current module for */
Cell op; { /* constructor functions etc...) */
Name n;
if (isNull(findBinding(textOf(op),bs))
&& (isNull(n=findName(textOf(op))) || !nameThisModule(n))) {
ERROR(0) "No top level definition for operator symbol \"%s\"",
textToStr(textOf(op))
EEND;
}
}
static Void local allNoPrevDef(b) /* ensure no previous bindings for*/
Cell b; { /* variables in new binding */
if (isVar(fst(b)))
noPrevDef(rhsLine(snd(hd(snd(snd(b))))),fst(b));
else {
Int line = rhsLine(snd(snd(snd(b))));
map1Proc(noPrevDef,line,fst(b));
}
}
static Void local noPrevDef(line,v) /* ensure no previous binding for */
Int line; /* new variable */
Cell v; {
Name n = findName(textOf(v));
if (isNull(n)) {
n = newName(textOf(v));
name(n).defn = PREDEFINED;
}
else if (name(n).defn!=PREDEFINED) {
ERROR(line) "Attempt to redefine variable \"%s\"",
textToStr(name(n).text)
EEND;
}
name(n).line = line;
}
/* --------------------------------------------------------------------------
* Static Analysis control:
* ------------------------------------------------------------------------*/
Void staticAnalysis(what)
Int what; {
switch (what) {
case INSTALL :
case RESET : daSccs = NIL;
patVars = NIL;
bounds = NIL;
bindings = NIL;
depends = NIL;
break;
case MARK : mark(daSccs);
mark(patVars);
mark(bounds);
mark(bindings);
mark(depends);
break;
}
}
/*-------------------------------------------------------------------------*/